#ifndef _WX_REGION_H_BASE_
#define _WX_REGION_H_BASE_

#include "wx/gdiobj.h"
#include "wx/gdicmn.h"

class wxBitmap;
class wxColour;
class wxRegion;

enum wxRegionContain {
  wxOutRegion = 0,
  wxPartRegion = 1,
  wxInRegion = 2
};

enum wxRegionOp {
  wxRGN_AND,

  // Creates a copy of the region
  wxRGN_COPY,

  // Combines the parts of first region that are not in the second one
  wxRGN_DIFF,

  // Creates the union of two combined regions.
  wxRGN_OR,

  // Creates the union of two regions except for any overlapping areas.
  wxRGN_XOR
};

class wxRegionBase : public wxGDIObject {
  public:
    bool operator==( const wxRegion& region ) const { return IsEqual( region ); }
    bool operator!=( const wxRegion& region ) const { return !( *this == region ); }
    bool Ok() const { return IsOk(); }
    bool IsOk() const { return m_refData != NULL; }
    virtual bool IsEmpty() const = 0;
    bool Empty() const { return IsEmpty(); }
    bool IsEqual( const wxRegion& region ) const;
    bool GetBox( wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h ) const
    { return DoGetBox( x, y, w, h ); }
    wxRect GetBox() const {
      wxCoord x, y, w, h;
      return DoGetBox( x, y, w, h ) ? wxRect( x, y, w, h ) : wxRect();
    }
    wxRegionContain Contains( wxCoord x, wxCoord y ) const
    { return DoContainsPoint( x, y ); }
    wxRegionContain Contains( const wxPoint& pt ) const
    { return DoContainsPoint( pt.x, pt.y ); }
    wxRegionContain Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
    { return DoContainsRect( wxRect( x, y, w, h ) ); }
    wxRegionContain Contains( const wxRect& rect ) const
    { return DoContainsRect( rect ); }
    virtual void Clear() = 0;
    bool Offset( wxCoord x, wxCoord y ) { return DoOffset( x, y ); }
    bool Offset( const wxPoint& pt ) { return DoOffset( pt.x, pt.y ); }
    bool Union( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) { return DoUnionWithRect( wxRect( x, y, w, h ) ); }
    bool Union( const wxRect& rect ) { return DoUnionWithRect( rect ); }
    bool Union( const wxRegion& region ) { return DoUnionWithRegion( region ); }

    #if wxUSE_IMAGE
    bool Union( const wxBitmap& bmp );
    bool Union( const wxBitmap& bmp, const wxColour& transp, int tolerance = 0 );
    #endif // wxUSE_IMAGE

    // Intersect rectangle or region with this one.
    bool Intersect( wxCoord x, wxCoord y, wxCoord w, wxCoord h );
    bool Intersect( const wxRect& rect );
    bool Intersect( const wxRegion& region ) { return DoIntersect( region ); }

    // Subtract rectangle or region from this:
    // Combines the parts of 'this' that are not part of the second region.
    bool Subtract( wxCoord x, wxCoord y, wxCoord w, wxCoord h );
    bool Subtract( const wxRect& rect );
    bool Subtract( const wxRegion& region ) { return DoSubtract( region ); }

    // XOR: the union of two combined regions except for any overlapping areas.
    bool Xor( wxCoord x, wxCoord y, wxCoord w, wxCoord h );
    bool Xor( const wxRect& rect );
    bool Xor( const wxRegion& region ) { return DoXor( region ); }


    // Convert the region to a B&W bitmap with the white pixels being inside
    // the region.
    wxBitmap ConvertToBitmap() const;

  protected:
    virtual bool DoIsEqual( const wxRegion& region ) const = 0;
    virtual bool DoGetBox( wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h ) const = 0;
    virtual wxRegionContain DoContainsPoint( wxCoord x, wxCoord y ) const = 0;
    virtual wxRegionContain DoContainsRect( const wxRect& rect ) const = 0;

    virtual bool DoOffset( wxCoord x, wxCoord y ) = 0;

    virtual bool DoUnionWithRect( const wxRect& rect ) = 0;
    virtual bool DoUnionWithRegion( const wxRegion& region ) = 0;

    virtual bool DoIntersect( const wxRegion& region ) = 0;
    virtual bool DoSubtract( const wxRegion& region ) = 0;
    virtual bool DoXor( const wxRegion& region ) = 0;
};

// some ports implement a generic Combine() function while others only
// implement individual wxRegion operations, factor out the common code for the
// ports with Combine() in this class
#if defined(__WXPALMOS__) || \
defined(__WXMSW__) || \
defined(__WXMAC__) || \
defined(__WXPM__)
#error mmmmmm

#define wxHAS_REGION_COMBINE

class wxRegionWithCombine : public wxRegionBase {
  public:
    // these methods are not part of public API as they're not implemented on
    // all ports
    bool Combine( wxCoord x, wxCoord y, wxCoord w, wxCoord h, wxRegionOp op );
    bool Combine( const wxRect& rect, wxRegionOp op );
    bool Combine( const wxRegion& region, wxRegionOp op ) { return DoCombine( region, op ); }


  protected:
    // the real Combine() method, to be defined in the derived class
    virtual bool DoCombine( const wxRegion& region, wxRegionOp op ) = 0;

    // implement some wxRegionBase pure virtuals in terms of Combine()
    virtual bool DoUnionWithRect( const wxRect& rect );
    virtual bool DoUnionWithRegion( const wxRegion& region );
    virtual bool DoIntersect( const wxRegion& region );
    virtual bool DoSubtract( const wxRegion& region );
    virtual bool DoXor( const wxRegion& region );
};

#endif // ports with wxRegion::Combine()

#include "wx/gtk/region.h"

inline bool wxRegionBase::Intersect( const wxRect& rect ) {
  return DoIntersect( wxRegion( rect ) );
}

inline bool wxRegionBase::Subtract( const wxRect& rect ) {
  return DoSubtract( wxRegion( rect ) );
}

inline bool wxRegionBase::Xor( const wxRect& rect ) {
  return DoXor( wxRegion( rect ) );
}

inline bool wxRegionBase::Intersect( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) {
  return Intersect( wxRect( x, y, w, h ) );
}

inline bool wxRegionBase::Subtract( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) {
  return Subtract( wxRect( x, y, w, h ) );
}

inline bool wxRegionBase::Xor( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) {
  return Xor( wxRect( x, y, w, h ) );
}

#ifdef wxHAS_REGION_COMBINE
#error mmmmmm

inline bool wxRegionWithCombine::Combine( wxCoord x,
    wxCoord y,
    wxCoord w,
    wxCoord h,
    wxRegionOp op ) {
  return DoCombine( wxRegion( x, y, w, h ), op );
}

inline bool wxRegionWithCombine::Combine( const wxRect& rect, wxRegionOp op ) {
  return DoCombine( wxRegion( rect ), op );
}

#endif // wxHAS_REGION_COMBINE

#endif // _WX_REGION_H_BASE_
